package com.jackrain.nea.ad.service;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.collect.Maps;
import com.jackrain.nea.ad.api.AdsequenceQueryCmd;
import com.jackrain.nea.config.Resources;
import com.jackrain.nea.exception.NDSException;
import com.jackrain.nea.exception.NDSObjectNotFoundException;
import com.jackrain.nea.exception.NDSRuntimeException;
import com.jackrain.nea.ext.sequence.dao.SequenceNumberDao;
import com.jackrain.nea.ext.sequence.entity.SequenceEntity;
import com.jackrain.nea.ext.sequence.enums.CycletypeEnum;
import com.jackrain.nea.ext.sequence.mapper.SequenceMapper;
import com.jackrain.nea.sys.CommandAdapter;
import com.jackrain.nea.util.ApplicationContextHandle;
import com.jackrain.nea.util.DateUtil;
import com.jackrain.nea.util.ValueHolder;
import com.jackrain.nea.web.query.DefaultWebEvent;
import com.jackrain.nea.web.query.QuerySession;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.thymeleaf.ITemplateEngine;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import redis.clients.jedis.exceptions.JedisConnectionException;

import java.util.Date;
import java.util.Locale;
import java.util.Map;

/**
 * @author xubin
 * 2017-12-11
 */
@Slf4j
@Component
@Service(protocol = "dubbo", validation = "true", version = "1.0", group = "ad")
public class AdsequenceQueryCmdImpl  extends CommandAdapter implements AdsequenceQueryCmd {

    private static ITemplateEngine templateEngine = new TemplateEngine();

    @Override
    public ValueHolder execute(QuerySession querySession) throws NDSException {

        ValueHolder vh = new ValueHolder();

        DefaultWebEvent event = querySession.getEvent();
        JSONObject param = JSON.parseObject(JSON.toJSONStringWithDateFormat(event.getData(), "yyyy-MM-dd HH:mm:ss", SerializerFeature.WriteMapNullValue), Feature.OrderedField);
        //判断是否有对应的代码生成器配置
        String sequenceName = param.getString("sequenceName");
        boolean isTest = param.getBoolean("isTest");
        JSONObject fixColumn = param.getJSONObject("fixcolumn");
        SequenceMapper sequenceMapper = ApplicationContextHandle.getBean(SequenceMapper.class);
        SequenceEntity sequence = sequenceMapper.findByName(StringUtils.upperCase(sequenceName));
        //没有直接抛出错误
        if (sequence == null) {
            throw new NDSObjectNotFoundException(Resources.getMessage("没有找到相应的序号规则", querySession.getLocale()));
        }

        //如果有，取出相应的规则
        String regex = sequence.getVformat();

        Map<String, Object> params = Maps.newHashMap();


        params.put("obj", fixColumn);//obj替换传进来的参数
        params.put("sn", 1);//sn替换流水号,模拟流水号以校验其他的值
        //校验除了流水号意外的参数
        String testResult = evel(regex, params, querySession.getLocale());
        //替换成功，则生成相应的流水号，将流水号替换到相应的占位符中
        if (isTest) {
            vh.put("result",testResult);
//            return testResult;
        }
        try {
            Integer serialNumber = generateSerialNumber(sequenceName, sequence.getIncrementno(), sequence.getCycletype(), Long.valueOf(sequence.getStartno()));
            if(sequence.getMaxno()!=null&& sequence.getMaxno()>0 && serialNumber>sequence.getMaxno()){
                throw new NDSRuntimeException(Resources.getMessage("超出最大流水号",querySession.getLocale()));
            }
            params.put("sn", serialNumber);
        } catch (JedisConnectionException e) {
            throw new NDSException(Resources.getMessage("无法连接到redis服务器，请稍后重试", querySession.getLocale()), e);
        }

//        return evel(regex, params, querySession.getLocale());
        log.info("result {}",evel(regex, params, querySession.getLocale()));
        vh.put("result", evel(regex, params, querySession.getLocale()));


        return vh;
    }

    private static String evel(String regex, Map<String, Object> params, Locale locale) {

        try {
            Context context = new Context(locale, params);
            return templateEngine.process(regex, context);
            //中间如果失败，抛出异常
        } catch (Exception e) {
            throw new NDSException(Resources.getMessage("序列号模板解析失败", locale), e);//抛出对应类型的自定义异常
        }

    }

    private static Integer generateSerialNumber(String sequenceName, Long increment, String cycletype, Long startNo) {
        SequenceNumberDao sequenceNumberDao = ApplicationContextHandle.getBean(SequenceNumberDao.class);


        String dateStr = "";
        //判断是否是当期的流水号
        if (StringUtils.isNotBlank(cycletype)) {
            CycletypeEnum cycletypeEnum = null;
            try {
                cycletypeEnum = CycletypeEnum.valueOf(StringUtils.upperCase(cycletype));
            } catch (Exception e) {
                cycletypeEnum = CycletypeEnum.N;
            }

            Date dt = new Date();
            switch (cycletypeEnum) {
                case N:
                    break;
                default:
                    dateStr = DateUtil.format(dt, cycletypeEnum.getDateFormater());
                    break;
            }

        }

        return sequenceNumberDao.setStartNo(sequenceName, dateStr, startNo, increment).intValue();


    }

}
